package com.xc.ezplan.log.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xc.ezplan.core.base.SearchCondition;
import com.xc.ezplan.core.dto.AdminUserDTO;
import com.xc.ezplan.core.utils.StringUtils;
import com.xc.ezplan.log.entity.AdminLog;
import com.xc.ezplan.log.service.AdminLogService;
import com.xc.ezplan.log.mapper.AdminLogMapper;
import lombok.RequiredArgsConstructor;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author lixingchen
 * @date 2022/11/20
 * @description 后台日志实现类
 */
@Service
@RequiredArgsConstructor
@Primary
public class AdminLogServiceImpl extends ServiceImpl<AdminLogMapper, AdminLog> implements AdminLogService {

	private final AdminLogMapper adminLogMapper;

	@Override
	public void saveLog(String username, String browser, String ip, ProceedingJoinPoint joinPoint, AdminLog log) {
		if (log == null) {
			throw new IllegalArgumentException("Log 不能为 null!");
		}
		MethodSignature signature = (MethodSignature) joinPoint.getSignature();
		Method method = signature.getMethod();
		com.xc.ezplan.log.annotation.Log aopLog = method.getAnnotation(com.xc.ezplan.log.annotation.Log.class);

		// 方法路径
		String methodName = joinPoint.getTarget().getClass().getName() + "." + signature.getName() + "()";

		// 描述
		log.setDescription(aopLog.value());

		log.setRequestIp(ip);
		log.setAddress(StringUtils.getCityInfo(log.getRequestIp()));
		log.setMethod(methodName);
		log.setUsername(username);
		log.setCreateTime(LocalDateTime.now());
		log.setParams(getParameter(method, joinPoint.getArgs()));
		// 记录登录用户，隐藏密码信息
		String login = "login";
		if (login.equals(signature.getName()) && StringUtils.isNotEmpty(log.getParams())) {
			JSONObject obj = JSONUtil.parseObj(log.getParams());
			log.setUsername(obj.getStr("username", ""));
			log.setParams(JSONUtil.toJsonStr(Dict.create().set("username", log.getUsername())));
		}
		log.setBrowser(browser);
		adminLogMapper.insert(log);
	}

	@Override
	public Object pageQueryLog(SearchCondition searchCondition, Page<AdminLog> page) {
		List<Date> createTime = searchCondition.getCreateTime();
		LambdaQueryWrapper<AdminLog> queryWrapper = new QueryWrapper<AdminLog>().lambda()
				.like(StringUtils.isNotBlank(searchCondition.getKeyWord()), AdminLog::getDescription,
						searchCondition.getKeyWord())
				.eq(AdminLog::getLogType, searchCondition.getLogType());
		if (!CollectionUtils.isEmpty(createTime) && createTime.size() == 2) {
			queryWrapper.between(AdminLog::getCreateTime, createTime.get(0), createTime.get(1));
		}
		return adminLogMapper.selectPage(page, queryWrapper);
	}

	@Override
	public Object queryErrorLogDetail(Long id) {
		AdminLog adminLog = adminLogMapper.selectById(id);
		byte[] exceptionDetail = adminLog.getExceptionDetail();
		return Dict.create().set("exception",
				new String(ObjectUtil.isNotNull(exceptionDetail) ? exceptionDetail : "".getBytes()));
	}

	@Override
	public void deleteAllLog(String logType) {
		adminLogMapper.delete(new QueryWrapper<AdminLog>().lambda().eq(AdminLog::getLogType, logType));
	}

	@Override
	public void deleteLog(Long logId) {
		adminLogMapper.deleteById(logId);
	}

	@Override
	public Object pageQueryUserLog(Page<AdminLog> page) {
		LambdaQueryWrapper<AdminLog> queryWrapper = new QueryWrapper<AdminLog>().lambda().eq(AdminLog::getUsername,
				((AdminUserDTO) StpUtil.getSession().get("userInfo")).getUsername());
		return adminLogMapper.selectPage(page, queryWrapper);
	}

	/**
	 * 根据方法和传入的参数获取请求参数
	 */
	private String getParameter(Method method, Object[] args) {
		List<Object> argList = new ArrayList<>();
		Parameter[] parameters = method.getParameters();
		for (int i = 0; i < parameters.length; i++) {
			// 将RequestBody注解修饰的参数作为请求参数
			RequestBody requestBody = parameters[i].getAnnotation(RequestBody.class);
			if (requestBody != null) {
				argList.add(args[i]);
			}
			// 将RequestParam注解修饰的参数作为请求参数
			RequestParam requestParam = parameters[i].getAnnotation(RequestParam.class);
			if (requestParam != null) {
				Map<String, Object> map = new HashMap<>(2);
				String key = parameters[i].getName();
				if (!StringUtils.isEmpty(requestParam.value())) {
					key = requestParam.value();
				}
				map.put(key, args[i]);
				argList.add(map);
			}
		}
		if (argList.isEmpty()) {
			return "";
		}
		return argList.size() == 1 ? JSONUtil.toJsonStr(argList.get(0)) : JSONUtil.toJsonStr(argList);
	}
}
